/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.web.ext.zul;

import cn.easyplatform.lang.Strings;
import cn.easyplatform.type.JmsObject;
import cn.easyplatform.utils.StringUtils;
import cn.easyplatform.web.ext.Exportable;
import cn.easyplatform.web.ext.Reloadable;
import cn.easyplatform.web.ext.Widget;
import cn.easyplatform.web.ext.ZkExt;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zul.*;
import org.zkoss.zul.event.PagingEvent;
import org.zkoss.zul.event.ZulEvents;

import java.util.List;
import java.util.Map;

/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public class GridExt extends Grid implements ZkExt, Reloadable {

    /**
     *
     */
    private static final long serialVersionUID = 8472104295591158010L;

    /**
     * 查询语句，可以有多个栏位
     */
    private Object _query;

    /**
     * 数据连接的资源id
     */
    private String _dbId;

    /**
     * 分组查询
     */
    private String _groupQuery;

    /**
     * 在显示时是否要马上执行查询
     */
    private boolean _immediate = true;

    /**
     * 分组显示标志
     */
    private String _groupField;

    /**
     * 分组名称标志
     */
    private String _groupNameField;

    /**
     * 列表头
     */
    private String _title;

    /**
     * 每一页的笔数
     */
    private int _pageSize = 20;

    /**
     * 排序
     */
    private String _orderBy;

    /**
     * 显示行数
     */
    private boolean _showRowNumbers;

    /**
     * 过滤表达式
     */
    private String _filter;

    /**
     * 分页组件是否显示详细信息
     */
    private boolean _pagingDetailed = true;

    /**
     * 分页组件显示模式
     */
    private String _pagingMold;

    /**
     * 分页组件显示style
     */
    private String _pagingStyle;

    /**
     * 头部风格
     */
    private String _headStyle;

    /**
     * 冻结的列数，从左到右开始
     */
    private int _frozenColumns;

    /**
     * 冻结头部风格
     */
    private String _frozenStyle = "background: #dfded8";

    /**
     * 行风格
     */
    private String _rowStyle;

    /**
     * 列头可否调整大小
     */
    private boolean _sizable = true;

    /**
     * 有几个列表头
     */
    private int _cols;

    /**
     * 前台逐行脚本
     */
    private String _rowScript;

    /**
     * 需要统计的栏位，可以多个，以逗分号分隔
     */
    private String _totalColumns;

    /**
     * 最后总计表达式
     */
    private String _totalScript;

    /**
     * groupQuery不为空时是否延时加载分组数据
     */
    private boolean _lazy;

    /**
     * 当pageSize大于0，fetchAll为true，表示获取所有的数据，不需要分页，使用本身的分页
     */
    private boolean _fetchAll;

    /**
     * 是否以交叉表方式显示
     */
    private boolean _cross;

    /**
     * 行表头查询
     */
    private String _rowQuery;

    /**
     * 是否必需重新加载
     */
    private boolean _force;

    /**
     * 联合多笔记录成一行
     */
    private int _unionRows = 1;

    public int getUnionRows() {
        return _unionRows;
    }

    public void setUnionRows(int unionRows) {
        this._unionRows = unionRows;
    }

    @Override
    public boolean isForce() {
        return _force;
    }

    public void setForce(boolean force) {
        this._force = force;
    }

    /**
     *
     */
    public GridExt() {
        super();
        setSpan(true);
    }

    public boolean isCross() {
        return _cross;
    }

    public void setCross(boolean cross) {
        this._cross = cross;
    }

    public String getRowQuery() {
        return _rowQuery;
    }

    public void setRowQuery(String rowQuery) {
        this._rowQuery = rowQuery;
    }

    /**
     * @return the fetchAll
     */
    public boolean isFetchAll() {
        return _fetchAll;
    }

    /**
     * @param fetchAll the fetchAll to set
     */
    public void setFetchAll(boolean fetchAll) {
        this._fetchAll = fetchAll;
    }

    /**
     * @return the lazy
     */
    public boolean isLazy() {
        return _lazy;
    }

    /**
     * @param lazy the lazy to set
     */
    public void setLazy(boolean lazy) {
        this._lazy = lazy;
    }

    /**
     * @return the totalColumns
     */
    public String getTotalColumns() {
        return _totalColumns;
    }

    /**
     * @param totalColumns the totalColumns to set
     */
    public void setTotalColumns(String totalColumns) {
        this._totalColumns = totalColumns;
    }

    /**
     * @return the totalScript
     */
    public String getTotalScript() {
        return _totalScript;
    }

    /**
     * @param totalScript the totalScript to set
     */
    public void setTotalScript(String totalScript) {
        this._totalScript = totalScript;
    }

    /**
     * @return the rowScript
     */
    public String getRowScript() {
        return _rowScript;
    }

    /**
     * @param rowScript the rowScript to set
     */
    public void setRowScript(String rowScript) {
        this._rowScript = rowScript;
    }

    /**
     * @return the groupQuery
     */
    public String getGroupQuery() {
        return _groupQuery;
    }

    /**
     * @param groupQuery the groupQuery to set
     */
    public void setGroupQuery(String groupQuery) {
        this._groupQuery = groupQuery;
    }

    /**
     * @return the cols
     */
    public int getCols() {
        return _cols;
    }

    /**
     * @param cols the cols to set
     */
    public void setCols(int cols) {
        this._cols = cols;
    }

    /**
     * @return
     */
    public boolean isSizable() {
        return _sizable;
    }

    /**
     * @param sizable
     */
    public void setSizable(boolean sizable) {
        this._sizable = sizable;
    }

    /**
     * @return the pagingMold
     */
    public String getPagingMold() {
        return _pagingMold;
    }

    /**
     * @param pagingMold the pagingMold to set
     */
    public void setPagingMold(String pagingMold) {
        this._pagingMold = pagingMold;
    }

    /**
     * @return the pagingStyle
     */
    public String getPagingStyle() {
        return _pagingStyle;
    }

    /**
     * @param pagingStyle the pagingStyle to set
     */
    public void setPagingStyle(String pagingStyle) {
        this._pagingStyle = pagingStyle;
    }

    /**
     * @return the pagingDetailed
     */
    public boolean isPagingDetailed() {
        return _pagingDetailed;
    }

    /**
     * @param pagingDetailed the pagingDetailed to set
     */
    public void setPagingDetailed(boolean pagingDetailed) {
        this._pagingDetailed = pagingDetailed;
    }

    public String getFilter() {
        return _filter;
    }

    public void setFilter(String filter) {
        this._filter = filter;
    }

    @Override
    public int getPageSize() {
        return _pageSize;
    }

    @Override
    public void setPageSize(int pageSize) {
        this._pageSize = pageSize;
        reload();
    }

    /**
     * @return the orderBy
     */
    public String getOrderBy() {
        return _orderBy;
    }

    /**
     * @param orderBy the orderBy to set
     */
    public void setOrderBy(String orderBy) {
        this._orderBy = orderBy;
    }

    /**
     * @return
     */
    public boolean isShowRowNumbers() {
        return _showRowNumbers;
    }

    /**
     * @param showRowNumbers
     */
    public void setShowRowNumbers(boolean showRowNumbers) {
        this._showRowNumbers = showRowNumbers;
    }

    public String getTitle() {
        return _title;
    }

    public void setTitle(String title) {
        this._title = title;
    }

    public String getGroupField() {
        return _groupField;
    }

    public String getGroupNameField() {
        return _groupNameField;
    }

    public void setGroupField(String groupField) {
        if (groupField != null)
            groupField = groupField.toUpperCase();
        this._groupField = groupField;
    }

    public void setGroupNameField(String groupNameField) {
        if (groupNameField != null)
            groupNameField = groupNameField.toUpperCase();
        this._groupNameField = groupNameField;
    }

    public boolean isImmediate() {
        return _immediate;
    }

    public void setImmediate(boolean immediate) {
        this._immediate = immediate;
    }

    public Object getQuery() {
        return _query;
    }

    public void setQuery(String query) {
        this._query = query;
    }

    public String getDbId() {
        return _dbId;
    }

    public void setDbId(String dbId) {
        this._dbId = dbId;
    }

    public String getRowStyle() {
        return _rowStyle;
    }

    public void setRowStyle(String rowStyle) {
        this._rowStyle = rowStyle;
    }

    public String getHeadStyle() {
        return _headStyle;
    }

    public void setHeadStyle(String headStyle) {
        this._headStyle = headStyle;
    }

    public int getFrozenColumns() {
        return _frozenColumns;
    }

    public void setFrozenColumns(int frozenColumns) {
        this._frozenColumns = frozenColumns;
    }

    public String getFrozenStyle() {
        return _frozenStyle;
    }

    public void setFrozenStyle(String frozenStyle) {
        this._frozenStyle = frozenStyle;
    }

    @Override
    public void reload() {
        Widget ext = (Widget) getAttribute("$proxy");
        if (ext != null)
            ext.reload(this);
    }

    public Component setColumnName(int index, String name) {
        Column header = getHeader(index);
        header.setLabel(name);
        return header;
    }

    public Component setColumnVisible(int index, boolean visible) {
        Column header = getHeader(index);
        header.setVisible(visible);
        return header;
    }

    public Column getHeader(int index) {
        return (Column) getColumns().getChildren().get(index);
    }

    public void export(String type) {
        Exportable export = (Exportable) getAttribute("$proxy");
        export.export(type);
    }

    public synchronized Row appendItem(Object data) {
        if (data instanceof JmsObject && ((JmsObject) data).getObject() instanceof Map) {
            Map<String, Object> map = (Map<String, Object>) ((JmsObject) data).getObject();
            Row li = new Row();
            if (!Strings.isBlank(_title)) {
                String[] headers = _title.split(",");
                List<Column> listheaders = this.getColumns().getChildren();
                for (int i = 0; i < headers.length; i++) {
                    Object val = map.get(headers[i]);
                    Label lc = new Label();
                    lc.setParent(li);
                    if (val != null) {
                        String format = listheaders.get(i).getValue();
                        if (!Strings.isBlank(format)) {
                            lc.setValue(StringUtils.format(format, val));
                        } else
                            lc.setValue(val.toString());
                    }
                }
            } else {
                List<Column> headers = this.getColumns().getChildren();
                for (Column header : headers) {
                    String name = header.getValue();
                    if (!Strings.isBlank(name)) {
                        Object value = map.get(name);
                        Label lc = new Label(value == null ? "" : value + "");
                        lc.setParent(li);
                    }
                }
            }
            li.setValue(data);
            getRows().getChildren().add(0, li);
            return li;
        }
        return null;
    }

    public Paging getPaging() {
        return _paging;
    }

    public void setPaging(Paging paging) {
        this._paging = paging;
    }

    public void repeat() {
        if (_paging != null) {
            int ap = _paging.getActivePage();
            if (ap == _paging.getPageCount() - 1)
                ap = 0;
            else
                ap = _paging.getActivePage() + 1;
            _paging.setActivePage(ap);
            if (this.getPaginal() == null)
                Events.postEvent(new PagingEvent(ZulEvents.ON_PAGING, _paging, ap));
        }
    }

    private Paging _paging;
}
